Windows應用程式介面(Windows API),或俗稱的WinAPI,是微軟Windows作業系統中的一套核心應用程式介面。Windows API這一叫法實際上是多個Windows平台上相似介面的統稱,這些介面也擁有各自的名字,如Win32 API。幾乎所有的Windows應用程式都在與 Windows API 進行互動。
Windows API將與Windows系統有關的複雜操作封裝在簡單的函式當中,編譯成動態連結媒體櫃,再隨Windows一同發布。開發者可以簡單地藉助這些函式來完成複雜的操作,有效降低了編寫Windows程式的難度。
Windows有一個軟體開發套件(SDK, software development kit)提供相應的文件和工具,以使程式設計師開發使用Windows API的軟體和利用Windows技術。
C是Windows API(Win32)的主要程式語言[1],在該API的文件中所公開的函式和資料結構均以該語言進行了描述。但是,如果某種程式語言能夠處理(明確定義的)低階資料結構,並能按照規定進行呼叫與回呼,那麼其編譯器或組譯器也可以呼叫Windows API。類似地,在歷史上Windows API也由多種語言進行了開發。[2]儘管C不是物件導向的程式語言,但Windows API和Windows都具有物件導向的特性;同時,也有許多物件導向語言的包裝類和擴充(如微軟基礎類別館MFC、視覺化組件媒體櫃VCL、GDI+等)使這種物件導向的結構更加清晰。例如,Windows 8提供的Windows API和WinRT API就是用C++[3]實現的,並且在設計上也是物件導向的[3]。
概述
Windows API所提供的功能可以歸為八類:[4]
提供了對Windows系統可用的基礎資源的訪問介面,包括檔案系統(file system)、外部裝置(device)、處理程序(process)、執行緒(thread)和錯誤處理(error handling)等。這些功能介面在16位元Windows中位於kernel.exe、krnl286.exe或krnl386.exe中;在32位元和64位元Windows下位於kernel32.dll和KernelBase.dll中。這些檔案在所有Windows的\Windows\System32 目錄中都可以被找到。
提供了對核心以外功能的訪問,包括登錄檔(Windows registry)、關閉/重新啟動系統(shutdown/restart)、服務(Windows Service)、使用者帳戶(user accounts)等。這些函式位於32位元Windows上的advapi32.dll和advapires32.dll中。
提供了將圖形內容輸出到監視器、印表機和其他外部輸出裝置的功能。它位於16位元Windows下的gdi.exe,以及32位元Windows下的gdi32.dll中。
提供了建立和管理視窗和大多數基本控制項(control)、接收滑鼠和鍵盤輸入,以及其他與GUI有關的功能。這些呼叫介面位於:16位元Windows下的user.exe,以及32位元Windows下的user32.dll。從Windows XP版本之後,基本控制項和通用對話方塊控制項(Common Control Library)的呼叫介面放在comctl32.dll中。
為應用程式提供標準對話方塊(如打開/儲存檔案對話方塊、顏色對話方塊和字型對話方塊等)。這個連結媒體櫃位於:16位元Windows下的commdlg.dll中,以及32位元Windows下的comdlg32.dll中。它被歸類為User Interface API之下。
為應用程式提供介面來訪問作業系統提供的一些進階控制項。比如像:狀態列(status bar)、進度條(progress bars)、工具列(toolbar)和標籤(tab)。這個連結媒體櫃位於:16位元Windows下的commctrl.dll中,以及32位元Windows下comctl32.dll中。它被歸類為User Interface API之下。使用API函式InitCommonControls或InitCommonControlsEx初始化(即註冊)相應的視窗類。InitCommonControlsEx實際註冊指定的通用控制項的視窗類。注意ICC_WIN95_CLASSES代表12個控制項類的集合。InitCommonControls是個空函式,但會使應用程式載入comctl32.dll;在comctl32.dll載入到處理程序時會在DLL的入口點呼叫InitCommonControlsEx註冊ICC_WIN95_CLASSES控制項類。
作為Windows API的組成部份,不僅允許應用程式訪問Windows Shell提供的功能,還對之有所改進和增強。它位於16位元Windows下的shell.dll中,以及32位元Windows下的shell32.dll中(Windows 95則在shlwapi.dll中)。它被歸類為User Interface API之下。
為訪問作業系統提供的多種網路功能提供介面。它包括NetBIOS、Winsock、NetDDE及遠程過程調用(RPC)等。
Internet Explorer網頁瀏覽器還公開了許多經常被應用程式呼叫的API,因此通常其也被視為是Windows API的一部份。IE從Windows 95 OSR2起就包含在了Windows系統中,並從Windows 98起開始為應用程式提供Web相關服務[13]。具體來說,它提供:
- 可嵌入的網頁瀏覽器控制項(以及 Trident / MSHTML 引擎),位於shdocvw.dll和mshtml.dll之中。
- urlmon.dll中的命名服務(URL moniters service),利用COM對象為應用程式提供解析URL服務。應用程式也可以為其他程式提供自己的URL處理程式。
- WinInet IE的網路層,支援HTTP和HTTPS等協定。
- 一個支援多種語言文字的連結媒體櫃(mlang.dll)。
- DirectX Transforms,一組圖像過濾組件。
- XML支援(MSXML組件)。
和Windows的郵件功能相關的API,例如位址本和郵件API,在Windows 7取消郵件功能之後也隨之從Windows API中去除。由於Windows Mail在Windows Vista上取代了Outlook Express,對應的API也隨之變化。
經典的Windows多媒體API位於winmm.dll中,包含了播放音訊、MIDI通訊、遊戲手柄及其他促進多媒體體驗的功能。該API源自Windows 3.x。
自從Windows 95 OSR2以來,Microsoft把DirectX API作為Windows安裝的一部份。DirectX提供一組鬆散相關的多媒體和遊戲服務,包括:
- Direct3D可以作為OpenGL的替代,來訪問3D加速硬體。
- DirectDraw提供硬體加速2D framebuffer(訊框緩衝)訪問介面。自DirectX 9以來,相比Direct3D更傾向於後者,因為Direct3D提供更全面的高效能圖形功能(畢竟2D彩現只是3D彩現的(不嚴格)子集)。已被Direct2D替代。
- DirectSound提供底層次的硬體加速音效卡訪問。被XAudio替代。
- DirectInput用來與輸入裝置(搖桿和gamepad)進行通訊。已被DirectX 9中引入的XInput所替代。
- DirectPlay提供一個多人遊戲的架構(multiplayer gaming infrastructure)。它已經被DirectX 9所替代,Microsoft不建議用它開發遊戲。
- DirectShow可以建立和執行通用的多媒體管道(generic multimedia pipelines)。它可以與GStreamer框架相媲美,並且經常被用來彩現遊戲影片和建立媒體播放器(Windows Media Player及諸如FFDShow之類的編解碼器正是基於此;但在Windows Vista及更高版本中,DirectShow被Media Foundation替代)。不建議用DirectShow開發遊戲。
- DirectMusic提供類似MIDI的功能。與DirectSound一起被XAudio替代。
Microsoft還提供了多個用於媒體編碼和播放的API:
- DirectShow,用於構建和執行通用的媒體管道。它類似於GStreamer框架,常用於彩現遊戲內的影片和構建媒體播放器(著名的Windows Media Player即基於它)。如今DirectShow已不再被推薦用於開發。
- Media Foundation,一種較新的數位媒體API,旨在取代DirectShow。
Windows API最重要功能即為此:處理作業系統和應用程式之間的互動。對於不同的Windows應用程式之間的通訊,Microsoft發展了一系列的技術並開發了最主要的Windows API。這些技術從動態資料交換(DDE)開始,隨後被對象連結和嵌入(OLE)取代,再被組件對象模型(COM)、自動化對象、ActiveX控制項和.NET框架取代。不過,這些技術之間區別並不總是十分明顯,並且有很多重疊之處。
這些技術的多樣性基本上是對軟體開發的不同方面進行細分的結果。自動化特別涉及了匯出應用程式和組件的功能為API,以便使其可以由其他應用程式而不是人類來進行控制。.NET是一種自包含的通用方法和技術,用於開發各種使用即時編譯語言編寫的桌面和Web應用程式。
Windows.pas是一個Pascal/Delphi單元,其中包含了Windows特定的API聲明。它在Pascal中的作用就像C中的windows.h一樣。
微軟利用許多更底層的Windows API函式,開發出許多封裝媒體櫃(wrapper),讓應用程式以更抽象的方式與Windows API進行互動。MFC(Microsoft Foundation Class Library)用C++ 類來封裝Windows API的功能,因而允許用更為物件導向的方式與API進行互動。ATL(Active Template Library)是對COM的面向範本(template oriented)的封裝。WTL(Windows Template Library)作為ATL的增強,被用來作為MFC的輕型的替代物。
其他著名的封裝媒體櫃是Borland公司的產品,為了與MFC競爭而推出的OWL(Object Windows Library)提供了類似的物件導向封裝。不久Borland又推出VCL(Visual Component Library)來取而代之。
大多數的Windows 程式框架(application framework)是對Windows API的封裝,因而.NET Framework、Java以及其他在Windows下的程式語言,都是(或者包含)封裝媒體櫃。
歷史
Windows API總會為程式設計師提供大量的構建不同 Windows的底層結構,這有助於為 Windows 程式設計師開發應用程式提供大量的靈活性和功能。但是,它同樣使Windows應用程式要負責處理大量底層且有時是繁瑣的與圖形化使用者介面(GUI)相關的操作。
例如,初學C的程式設計師通常會把編寫簡單的「Hello world」作為他們的第一項任務。程式的工作部份僅僅是主程式中的一個printf行,在連結到標準I/O媒體櫃時也僅需要一個include行:
#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
}
Windows版本的工作部份仍然只有一行程式碼,但除此之外它需要很多很多行的額外開銷。
許多有關Windows API的暢銷書的作者查爾斯·佩佐德(Charles Petzold)曾經說過:[14]
“ | Windows 1.0 SDK中的最初的Hello world程式或多或少沾了些醜聞。HELLO.C大約有150行,而HELLO.RC資源指令碼還多加了大約20多行……在接觸到Windows 的Hello world程式時,資深的C程式員通常會驚恐或大笑起來。 | ” |
——查爾斯·佩佐德(Charles Petzold),Programming Microsoft Windows with C# |
這些年來,Windows作業系統已經今非昔比,而Windows API也隨之改變和成長並反映出這種變化。Windows API的Windows 1.0版本只提供不到450個函式調用(Subroutine),而現在的版本提供上千個。然而,整體而言,Windows介面保持了相當好的一致性,習慣於現在版本Windows API的程式設計師對古老的Windows 1.0程式也並不會陌生。[15]
微軟特別強調維持軟體的向下相容性。為了實現此一目標,有時微軟甚至不惜支援使用了非官方乃至(編程上)非法的API的軟體。一位致力於Windows API的Windows開發者雷蒙德·陳(Raymond Chen)曾提及:[16]
“ | 僅僅是關於應用程式所做出的壞事以及我們讓應用程式重新運作所必須(通常是在不由自主的情況下)採用的方法,我可能會寫上幾個月。這就是在人們指責微軟在作業系統升級期間惡意破壞應用程式時,我會特別憤怒的原因。如果有任何無法在Windows95上執行的應用程式,我會將這些應用程式視為個人故障。 | ” |
——Raymond Chen,What about BOZOSLIVEHERE and TABTHETEXTOUTFORWIMPS? |
對Windows API來說,其歷史上最大的變化之一就是從Win16(在Windows 3.1及更早的版本中提供)到Win32(Windows NT和Windows 95及更高版本)的過渡。雖然Win32早已在Windows NT 3.1中引入,並在Windows 95前就已允許使用,但直到Windows 95應用程式才開始廣泛移植到Win32。為了簡化轉換的過程,在Windows 95中對Microsoft內外的開發人員Windows使用了一種複雜的API thunk方案來允許32位元程式碼呼叫到16位元程式碼(對大多數Win16 API有效),反之亦然。同樣的,64位元的Windows也可以通過WoW64執行32位元的應用程式,而位於Windows目錄下的SysWOW64資料夾中包含了多個用於支援32位元應用程式的工具。
版本
幾乎每個版本的Windows都引入了其對Windows API的添加和修改[17],但是API的名稱在不同版本的Windows間保持了一致,並且僅當Windows主要的架構和平台都更改時API的名稱才會改變。Microsoft最終將當時名叫Win32的API家族改名為Windows API,並使其成為過去和未來API版本的統稱。
- Win16是第一個16位元版本Windows的API。它最早被簡單地叫做Windows API,但後來為了與較新的32位元API區分,它被重新命名為了Win16。Win16 API的功能主要駐留在作業系統的核心檔案中,如kernel.exe(或krnl286.exe、krnl386.exe)、user.exe和gdi.exe。值得一提的是,儘管這些檔案採用了exe的副檔名,它們本質上其實是動態連結媒體櫃。
- Win32是Windows 95及後續版本的32位元API。與Win16相同,這個API由在系統DLL中實現的函式組成。Win32的核心檔案是kernel32.dll、user32.dll和gdi32.dll。Win32最早在Windows NT中引入,而不是Windows 95。Windows 95中的Win32最早被稱為Win32c,其中的「c」表示相容性(英語:compatibility);這個名稱後來被微軟捨棄,轉而使用Win32。
- Win32s是Windows 3.1x系列的擴充,它為這些系統實現了Win32 API的一部份功能。其中的「s」表示子集(英語:subset)。
- Win64是64位元Windows上的Windows API變體。此時應用程式的32位元和64位元版本可以從同一個程式碼媒體櫃進行編譯。在預設情況下,所有主記憶體指標都是64位元的(LLP64型),因此部份程式的原始碼必須被重寫以相容64位元指標演算法。
- WinCE是Windows CE作業系統中的Windows API。
其它實現
儘管微軟的Windows API實現有著作權保護,但被普遍認可的是,根據美國的法律先例,其他廠商仍然可以通過提供一致的API來類比Windows,而不會侵犯著作權。
Wine專案為類Unix平台提供了一個在Linux核心API與Windows API程式之間的Win32 API相容層。ReactOS則更進一步,想要實現一個完整的Windows作業系統;它通過與Wine專案的密切合作來促進其程式碼的重用和相容。DosWin32和HX DOS-Extender是另外兩個類比Windows API的專案,它們允許通過DOS命令列來執行簡單的Windows程式。Odin是一個在OS/2平台上類比Win32的專案。
編譯器支援
為了開發使用Windows API的軟體,編譯器必須能處理和匯入微軟相關的DLLs或者COM對象。編譯器必須接受一種C或C++方言,或者能夠處理揭示了內部API函式名稱的介面定義語言(Interface description language)檔案和標頭檔及生成的類型媒體櫃(Type Library)。概括而言,這些預備條件(編譯器、開發工具、媒體櫃和標頭檔)被統稱為Microsoft Platform SDK。很長時間以來,包含了編譯器和開發工具的專利產品如Microsoft Visual Studio系列和Borland編譯器(儘管至少在Windows下,SDK是可以從整個IDE環境中剝離出來單獨免費下載的,據Microsoft Platform SDK Update),是僅有的能提供整套開發環境的選擇。如今MinGW和Cygwin也能提供一套這樣的開發環境——是基於採用一種獨立標頭檔集合來保證能與微軟DLL連接的GCC。LCC-Win32是由Jacob Navia維護的一種「非商業用途免費」的C編譯器。Pellesc是由Pelle Orinius維護的一種免費C編譯器。MASM32是一個成熟的專案,它通過自製或由SDK平台轉換的標頭檔和媒體櫃,並利用32位元微軟組譯器來實現支援Windows API。
微軟相關的編譯器支援也是例外處理(Structured Exception Handling)特性所需要的。這個體制有雙重目的:它提供了語言相關的例外處理賴以實現的基礎,同時也是核心藉以通知程式發生諸如解除一個非法指標的參照或堆疊溢位之類異常狀況的管道。甫一被引入Windows 95和NT,微軟/Borland C++編譯器就有使用這種體制的能力,然而實際實現未被公開,而且必須經過反向工程方可用於Wine專案和免費編譯器。SEH的執行機制是先把異常的控制代碼推入堆疊,繼而將它們添加到儲存於執行緒本機資源(即執行緒環境塊的首欄位)的一個鏈結串列里。事實上,每一個未有程式本身處理的異常,都將由會彈出常規Windows崩潰對話方塊的預設backstop處理器處理。
API在Visual Basic中的實現範例(這個簡化的例子使得使用者可以讓命令按鈕在表單上四處移動):
Private Const WM_NCLBUTTONDOWN As Long = &HA1&
Private Const HTCAPTION As Long = 2&
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd&, ByVal wMsg&, wParam As Any, lParam As Any) As Long
If Command1.MousePointer = 14 Then
Call ReleaseCapture
Call SendMessage(Command1.hWnd, WM_NCLBUTTONDOWN, ByVal HTCAPTION, ByVal 0&)
End If